/* eslint-disable no-unused-vars */
import { SUCCESS_CODE } from '@/constants';
import { HOST } from '@/services/create-api';
import { getToken } from '@/utils/storage';
import { InboxOutlined, PlusOutlined, UploadOutlined } from '@ant-design/icons';
import { Button, message, Modal, Upload } from 'antd';
import ImgCrop from 'antd-img-crop';
import classNames from 'classnames';
import {
  forwardRef,
  useEffect,
  useImperativeHandle,
  useRef,
  useState,
} from 'react';
import {
  CROP_PROPS,
  getAcceptTypes,
  getDefaultPreFileUrl,
  getFileUrlByBase64,
  PREVIEW_TYPE,
  previewFile,
  UPLOAD_TYPE,
  validateFileType,
} from './fileUtils';
import styles from './index.less';

const { Dragger } = Upload;
const token = getToken();

interface FileItem {
  uid: string;
  name: string;
  status?: any;
  url?: string;
  response?: any;
  ossId?: string;
  originFileObj?: any;
}

// Utility function to convert file to base64
function parseFileToBase64(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result as string);
    reader.onerror = (error) => reject(error);
  });
}

const FileUpload = forwardRef<any, FileUploadProps>(
  (
    {
      value = [],
      onChange = () => {},
      fileLen = 20,
      uploadType = UPLOAD_TYPE.BUTTON.code,
      icon = <UploadOutlined />,
      style,
      className,
      disabled = false,
      action = `${HOST}/system/oss/upload`,
      accept = ['jpg', 'jpeg', 'png', 'pdf', 'xls', 'xlsx', 'doc', 'docx'],
      limitSize = 20,
      tooltipTitle = '支持扩展名：.jpg .jpeg .png .pdf .xls .xlsx .doc .docx',
      suffix = true,
      text = '点击上传',
      domProps = {},
      extraLine,
      isHand,
      extraParams = {},
      id,
      getPreFileUrl = getDefaultPreFileUrl,
      manual = false,
      resFileMap = {
        fileName: 'name',
        fileKey: 'ossId',
      },
      reqFileMap = {
        file: 'file',
        fileName: 'fileName',
      },
      imgCropProps = {},
      crop = false,
      transferBlob = false,
      previewType = PREVIEW_TYPE.PREVIEW.code,
      children,
      ...props
    },
    ref,
  ) => {
    const uploadRef = useRef<any>();
    const [fileList, setFileList] = useState<FileItem[]>(value || []);
    const [fileKeysList, setFileKeysList] = useState<FileItem[]>(value || []);
    const strClass = classNames(styles.myUpload, className);
    const [previewVisible, setPreviewVisible] = useState(false);
    const [previewImg, setPreviewImg] = useState<{
      title: string;
      image: string;
    }>({ title: '', image: '' });

    const triggerChange = (list: FileItem[]) => {
      setFileKeysList(list);
      return onChange && onChange(list);
    };

    const handleRemove = (file: FileItem) => {
      const index = fileList.indexOf(file);
      const newFileList = fileList.slice();
      const newFileKeysList = fileKeysList.filter(
        (item) => item.uid !== file.uid,
      );
      newFileList.splice(index, 1);
      triggerChange(newFileKeysList);
      setFileList(newFileList);
    };

    useImperativeHandle(ref, () => ({
      fileList,
      setFileList: (val: FileItem[]) => {
        setFileKeysList(val);
        setFileList(val);
      },
      onRemove: handleRemove,
    }));

    useEffect(() => {
      if (fileList.length === 0 && Array.isArray(value) && value.length > 0) {
        setFileKeysList(value);
        setFileList(value);
      }
    }, [value]);

    const validateFileBeforeUpload = (
      file: any,
      fList: FileItem[],
      limit = 5,
    ) => {
      const limitType = validateFileType(accept, file, suffix);
      if (!limitType) {
        message.error('请按照正确格式上传');
        return false;
      }
      const isLimited = file.size / 1024 / 1024 < limit;
      if (!isLimited) {
        message.error(`请上传${limit}MB以下的文件`);
        return false;
      }
      if (fileLen > 1) {
        const disLen = fileList.length + fList.length - fileLen;
        const newfList = fList.slice(fileLen - fileList.length);
        if (disLen > 0 && newfList.includes(file)) {
          message.error(`最多上传${fileLen}份文件`);
          return false;
        }
      }
      if (manual) {
        triggerChange([...fileList, file]);
        setFileList([...fileList, file]);
        return false;
      }
      if (transferBlob) {
        return new Promise((resolve) => {
          const reader = new FileReader();
          reader.readAsDataURL(file);
          reader.onload = () => {
            resolve(reader.result);
          };
        });
      }
      return true;
    };

    const handleChange = (info: any) => {
      const { file, fileList: infoFileList } = info;
      let fList: FileItem[] = [];
      fList = (fileLen === 1 ? infoFileList.slice(-1) : infoFileList).filter(
        (f: any) => !!f.status,
      );
      if (!file.status) return;

      fList.forEach((f, index) => {
        if (
          f.status === 'done' &&
          f.response &&
          f.response.code === SUCCESS_CODE
        ) {
          const { data } = f.response;
          fList[index] = {
            ...fList[index],
            ...data,
          };
        }
      });
      const fKeys = fList.reduce((keys: any[], f) => {
        const hasRes = f && f.response && f.response.code === SUCCESS_CODE;
        const isDone = f.status === 'done';
        if (isDone && hasRes) {
          // 手动上传整个文件
          if (isHand) {
            keys.push({
              ossId: f.ossId,
              name: f.name,
              uid: f.uid,
              url: f.url,
              status: 'done',
              wholeFile: file,
            });
          } else {
            keys.push({
              ossId: f.ossId,
              name: f.name,
              uid: f.uid,
              url: f.url,
              status: 'done',
            });
          }
        }
        return keys;
      }, []);
      setFileList(fList);
      if (file && file.status === 'done') {
        triggerChange(fKeys);
      }
    };

    // 如果传入了customchange那么就onChange整个文件

    const handleImgPreview = async (file: FileItem) => {
      let { url } = file;
      if (!url) {
        const base64 = await parseFileToBase64(file?.originFileObj);
        url = getFileUrlByBase64(base64);
      }
      setPreviewVisible(true);
      setPreviewImg({
        title: file.name,
        image: url,
      });
    };

    const handleUploadPreview = async (file: FileItem) => {
      let { url } = file;
      if (!url) {
        const base64 = await parseFileToBase64(file.originFileObj);
        url = getFileUrlByBase64(base64);
      }
      return previewFile(url, file.name, previewType);
    };

    const uploadProps = {
      action,
      name: 'file',
      multiple: fileLen > 1,
      withCredentials: true,
      fileList,
      accept: getAcceptTypes(accept, suffix),
      beforeUpload: (file: any, fList: any[]) =>
        validateFileBeforeUpload(file, fList, limitSize) as any,
      onChange: handleChange as any,
      onRemove: handleRemove as any,
      disabled,
      maxCount: fileLen,
      onPreview: handleUploadPreview,
      headers: { Authorization: token as string },
      ...props,
    };

    const ImgUpload = (
      <Upload
        listType="picture-card"
        {...uploadProps}
        onPreview={handleImgPreview as any}
      >
        {fileList.length >= fileLen || disabled ? null : (
          <div
            style={{
              height: 104,
              width: 104,
              display: 'flex',
              alignItems: 'center',
              flexDirection: 'column',
              justifyContent: 'center',
            }}
            {...domProps}
          >
            <PlusOutlined />
            <div style={{ marginTop: 8 }}>上传图片</div>
          </div>
        )}
      </Upload>
    );

    switch (uploadType) {
      case UPLOAD_TYPE.DRAG.code:
        return (
          <Dragger {...uploadProps} style={style} ref={uploadRef}>
            <p className="ant-upload-drag-icon">
              <InboxOutlined />
            </p>
            <p className="ant-upload-text">点击或将文件拖拽到这里上传</p>
            <p className="ant-upload-hint">{tooltipTitle}</p>
          </Dragger>
        );

      case UPLOAD_TYPE.PICTURE.code:
        return (
          <div className={strClass} id={id}>
            {crop ? (
              <ImgCrop rotate grid {...CROP_PROPS} {...imgCropProps}>
                {ImgUpload}
              </ImgCrop>
            ) : (
              ImgUpload
            )}
            <Modal
              open={previewVisible}
              title={previewImg.title}
              footer={null}
              onCancel={() => setPreviewVisible(false)}
            >
              <img
                alt="预览图片"
                style={{ width: '100%' }}
                src={previewImg.image}
              />
            </Modal>
          </div>
        );

      case UPLOAD_TYPE.TEXT.code:
        return (
          <Upload {...uploadProps} {...props} style={style} ref={uploadRef}>
            <a {...domProps}>
              {icon} {text}
            </a>
          </Upload>
        );

      case UPLOAD_TYPE.BUTTON.code:
        return (
          <div className={strClass} id={id}>
            <Upload {...uploadProps} style={style} ref={uploadRef}>
              <Button block={false} disabled={disabled} {...domProps}>
                {icon} {text}
              </Button>
              <p
                className="ant-upload-hint"
                style={{ marginTop: 5, color: 'rgba(0, 0, 0, 0.45)' }}
              >
                {tooltipTitle}
              </p>
              {extraLine}
            </Upload>
          </div>
        );

      case UPLOAD_TYPE.CUSTOM.code:
        return (
          <div className={strClass} id={id}>
            <Upload {...uploadProps} style={style} ref={uploadRef}>
              {children}
            </Upload>
          </div>
        );

      default:
        return <div>未知的上传类型</div>;
    }
  },
);

export default FileUpload;
